﻿using CPPEI.Coolzon.UI.XProperty.Converters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;

namespace CPPEI.Coolzon.UI.Views
{
    public class PartInstanceCache
    {
        public static Dictionary<string, Part> s_partInstanceDictionary = new Dictionary<string, Part>();

        public static Part GetPartInstance(string name)
        {
            if (s_partInstanceDictionary.ContainsKey(name))
            {
                return s_partInstanceDictionary[name];
            }

            return null;
        }

        private static ConvertContext s_convertContext;

        public static void SetConvertContext(ConvertContext convertContext)
        {
            s_convertContext = convertContext;
        }

        public static void Reset()
        {
            s_partInstanceDictionary.Clear();
        }

        /// <summary>
        /// 清除缓存中的所有组件
        /// </summary>
        public static void ClearAllParts()
        {
            s_partInstanceDictionary.Clear();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="convertContext"></param>
        /// <param name="type"></param>
        /// <param name="sceneMetadata"></param>
        /// <param name="loadFromCache">是否从缓存中加载，true从缓存中加载，false每次都重新创建实例</param>
        /// <returns></returns>
        public static UI.Part GetSceneInstance(string type, Metadata.Scene sceneMetadata, bool loadFromCache)
        {
            if (loadFromCache)
            {
                if (s_partInstanceDictionary.ContainsKey(sceneMetadata.Name))
                {
                    System.Diagnostics.Debug.WriteLine("load scene from cache:{0}", sceneMetadata.Name);
                    return s_partInstanceDictionary[sceneMetadata.Name];
                }

                UI.Part scene = PartFactory.CreatePart("scene", sceneMetadata.Name);
                (scene as UI.ScenePart).IsHorizontalLoopRender = sceneMetadata.IsHorizontalLoopRender;
                BuildScene(s_convertContext, scene as UI.ScenePart, sceneMetadata);
                s_partInstanceDictionary.Add(sceneMetadata.Name, scene);
                return scene;
            }
            else
            {
                UI.Part scene = PartFactory.CreatePart("scene", sceneMetadata.Name);
                (scene as UI.ScenePart).IsHorizontalLoopRender = sceneMetadata.IsHorizontalLoopRender;
                BuildScene(s_convertContext, scene as UI.ScenePart, sceneMetadata);
                return scene;
            }
        }

        public static UI.Part GetAreaInstance(Metadata.Scene sceneMetadata, Metadata.Area areaMetadata)
        {
            if (s_partInstanceDictionary.ContainsKey(areaMetadata.Name))
            {
                System.Diagnostics.Debug.WriteLine("load area from cache:{0}", areaMetadata.Name);
                return s_partInstanceDictionary[areaMetadata.Name];
            }

            UI.Part part = PartFactory.CreatePart("Area", areaMetadata.Name);
            BuildArea(s_convertContext, part as UI.AreaPart, areaMetadata);
            s_partInstanceDictionary.Add(sceneMetadata.Name, part);
            return part;
        }

        /// <summary>
        /// 根据组件库项目来创建组件实例
        /// </summary>
        /// <param name="partLibItem"></param>
        /// <returns></returns>
        public static UI.Part GetPartInstance(Metadata.PartLibItem partLibItem)
        {
            return PartFactory.CreatePart(partLibItem);
        }

        #region private methods

        private static void BuildScene(ConvertContext convertContext, UI.ScenePart scene, Metadata.Scene sceneMetadata)
        {
            scene.Caption = sceneMetadata.Caption;
            scene.SetMetadata(sceneMetadata);

            BuildProperties(convertContext, scene, sceneMetadata.Properties);
            BuildParameters(scene, sceneMetadata);

            //if (Metadata.SolutionUtil.GetProperty(sceneMetadata.Properties, "WIDTH") == null)
            //{
            //    scene.Width = UIContext.Current.SolutionWidth;
            //}
            //if (Metadata.SolutionUtil.GetProperty(sceneMetadata.Properties, "HEIGHT") == null)
            //{
            //    scene.Height = UIContext.Current.SolutionHeight;
            //}


            if (sceneMetadata.Areas != null)
            {
                if (sceneMetadata.IsAllowSwapArea)
                {
                    double leftOffset = 0;
                    for (int areaIndex = 0; areaIndex < sceneMetadata.Areas.Count; areaIndex++)
                    {
                        Metadata.Area areaMetadata = sceneMetadata.Areas[areaIndex];
                        UI.Part areaPart = PartFactory.CreatePart("area", areaMetadata.Name);
                        areaPart.Scene = scene;
                        areaPart.XCaption = areaMetadata.Caption;
                        BuildArea(convertContext, (UI.AreaPart)areaPart, areaMetadata);
                        areaPart.XLeft = leftOffset;
                        leftOffset += areaPart.XWidth + areaPart.XMargin.Left + areaPart.XMargin.Right;
                        areaPart.XTop = 0;
                        areaPart.XHeight = scene.XHeight;
                        scene.AddPart(areaPart);
                        scene.ChildrenPosInfo.Set(areaMetadata.Name, areaPart.XLeft);
                        //areaPart.Init();
                    }
                }
                else
                {
                    for (int areaIndex = 0; areaIndex < sceneMetadata.Areas.Count; areaIndex++)
                    {
                        Metadata.Area areaMetadata = sceneMetadata.Areas[areaIndex];
                        UI.Part areaPart = PartFactory.CreatePart("area", areaMetadata.Name);
                        areaPart.Scene = scene;
                        areaPart.XCaption = areaMetadata.Caption;
                        BuildArea(convertContext, (UI.AreaPart)areaPart, areaMetadata);
                        //layout.AddPart(area.Frame, areaPart);
                        //areaPart.ParentPart = scene;
                        scene.AddPart(areaPart);
                        scene.ChildrenPosInfo.Set(areaMetadata.Name, areaPart.XLeft);
                        //areaPart.Init();
                    }
                }
            }
            //scene.Active();
        }

        /*
        private static void BuildLayout(UI.Layout layout, Metadata.Layout layoutMetadata)
        {
            if (layoutMetadata == null || layoutMetadata.Frames == null)
            {
                return;
            }

            for (int index = 0; index < layoutMetadata.Frames.Count; index++)
            {
                Metadata.Frame frameMetadata = layoutMetadata.Frames[index];
                UI.PartFrame frame = new PartFrame();
                frame.Name = frameMetadata.Name;
                if (!string.IsNullOrEmpty(frameMetadata.Width) && frameMetadata.Width != "*")
                {
                    frame.Width = Convert.ToInt16(frameMetadata.Width);
                }
                if (!string.IsNullOrEmpty(frameMetadata.Height) && frameMetadata.Height != "*")
                {
                    frame.Height = Convert.ToInt16(frameMetadata.Height);
                }
                layout.AddFrame(frameMetadata.Pos, frame);
                
                // 
                BuildFrame(frame, frameMetadata);
            }
        }
        */

        /*
        private static void BuildFrame(UI.PartFrame frame, Metadata.Frame frameMetadta)
        {
            if (frameMetadta.Layout != null)
            {
                UI.Layout layout = PartFactory.CreateLayout(frameMetadta.Layout.Type);
                layout.AttachToPart(frame);
                frame.Layout = layout;
                BuildLayout(layout, frameMetadta.Layout);
            }
        }*/

        private static void BuildArea(ConvertContext convertContext, UI.AreaPart areaPart, Metadata.Area areaMetadata)
        {
            //(areaPart as AreaPart).IsShowHeader = areaMetadata.IsShowHeader;
            //(areaPart as AreaPart).Caption = areaMetadata.Caption;

            areaPart.SetMetadata(areaMetadata);

            BuildProperties(convertContext, areaPart, areaMetadata.Properties);
            BuildParameters(areaPart, areaMetadata);

            //UI.Layout layout = PartFactory.CreateLayout(areaMetadata.Layout.Type);
            //layout.AttachToPart(areaPart);
            //areaPart.Layout = layout;
            //BuildLayout(layout, areaMetadata.Layout);

            // 构造区域里的子区域
            if (areaMetadata.Areas != null && areaMetadata.Areas.Count > 0)
            {
                for (int index = 0; index < areaMetadata.Areas.Count; index++)
                {
                    Metadata.Area subAreaMetadata = areaMetadata.Areas[index];
                    UI.Part subAreaPart = PartFactory.CreatePart("area", subAreaMetadata.Name);
                    subAreaPart.Scene = areaPart.Scene;
                    //subAreaPart.XCaption = subAreaMetadata.Caption;
                    BuildArea(convertContext, (UI.AreaPart)subAreaPart, subAreaMetadata);
                    //layout.AddPart(subAreaMetadata.Frame, subAreaPart);
                    //subAreaPart.ParentPart = areaPart;
                    ((UI.AreaPart)areaPart).AddPart(subAreaPart);
                    //subAreaPart.Init();
                }
            }

            if (areaMetadata.Parts != null && areaMetadata.Parts.Count > 0)
            {
                for (int index = 0; index < areaMetadata.Parts.Count; index++)
                {
                    Metadata.Part partMetadata = areaMetadata.Parts[index];
                    UI.Part part = PartFactory.CreatePart(partMetadata.Type, partMetadata.Name);
                    part.Scene = areaPart.Scene;
                    //part.XCaption = partMetadata.Caption;
                    (part as UI.Part).SetMetadata(partMetadata);
                    BuildPart(convertContext, part, partMetadata);
                    //layout.AddPart(partMetadata.Frame, part);
                    //part.ParentPart = areaPart;
                    ((UI.AreaPart)areaPart).AddPart(part);
                    //part.Init();
                }
            }
        }

        public static void BuildPart(UI.Part part, Metadata.Part partMetadata)
        {
            part.SetMetadata(partMetadata);
            BuildPart(new ConvertContext(), part, partMetadata);
        }

        private static void BuildPart(ConvertContext convertContext, UI.Part part, Metadata.Part partMetadata)
        {
            BuildProperties(convertContext, part, partMetadata.Properties);
            BuildParameters(part, partMetadata);
            BuildEvents(part, partMetadata.Events);

            if (part is IPartContainer)
            {
                if (partMetadata.Parts != null && partMetadata.Parts.Count > 0)
                {
                    for (int index = 0; index < partMetadata.Parts.Count; index++)
                    {
                        Metadata.Part subPartMetadata = partMetadata.Parts[index];
                        UI.Part subPart = PartFactory.CreatePart(subPartMetadata.Type, subPartMetadata.Name);
                        subPart.Scene = part.Scene;
                        subPart.XCaption = subPartMetadata.Caption;
                        (subPart as UI.Part).SetMetadata(subPartMetadata);
                        BuildPart(convertContext, subPart, subPartMetadata);
                        //layout.AddPart(partMetadata.Frame, part);
                        //part.ParentPart = areaPart;

                        ((UI.IPartContainer)part).AddPart(subPart);

                        //subPart.Init();
                    }
                }
            }
        }

        /// <summary>
        /// 给组件注入属性
        /// </summary>
        /// <param name="part"></param>
        /// <param name="properties"></param>
        private static void BuildProperties(ConvertContext convertContext, UI.Part part, List<Metadata.Property> properties)
        {
            //XPropertyUtility.LoadXProperties(part, new Type[]{
            //    typeof(ImageSource),
            //    typeof(ImageSource[])
            //});
            
            XPropertyUtility.LoadXPropertyValue(convertContext, part, properties);
        }

        /// <summary>
        /// 注入事件信息
        /// </summary>
        /// <param name="part"></param>
        /// <param name="events"></param>
        private static void BuildEvents(UI.Part part, List<Metadata.Event> events)
        {
            part.EventList = events;
        }

        /// <summary>
        /// 注入参数信息
        /// </summary>
        /// <param name="part"></param>
        /// <param name="metadataNode"></param>
        private static void BuildParameters(UI.Part part, Metadata.NodeBase metadataNode)
        {
            if (metadataNode.Parameters != null)
            {
                for (int index = 0; index < metadataNode.Parameters.Count; index++)
                {
                    part.Parameters.Add(metadataNode.Parameters[index].Clone() as Metadata.Parameter);
                }
            }
        }
        #endregion
    }
}
